using System;
using System.Collections.Generic;
using System.Text;

namespace SmartMathLibrary
{
    /// <summary>
    /// This class represents a simple mathematic polynomial for real numbers.
    /// </summary>
    [Serializable]
    public class SimplePolynomial : AbstractRealPolynomial, ISimplePolynomial, IRealFunction
    {
        /// <summary>
        /// Represents the coefficients of the polynomial.
        /// </summary>
        private Double[] coefficients;

        /// <summary>
        /// Initializes a new instance of the <see cref="SimplePolynomial"/> class.
        /// </summary>
        /// <param name="degree">The degree of the polynomial.</param>
        public SimplePolynomial(int degree)
        {
            if (degree + 1 < 0)
            {
                throw new ArgumentException("degree + 1 < 0", "degree");
            }

            this.coefficients = new Double[degree + 1];
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="SimplePolynomial"/> class.
        /// </summary>
        /// <param name="firstCoeffientValue">The first coefficient value x^0.</param>
        public SimplePolynomial(double firstCoeffientValue)
        {
            this.coefficients = new Double[1];
            this.coefficients[0] = firstCoeffientValue;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="SimplePolynomial"/> class.
        /// </summary>
        /// <param name="firstCoeffientValue">The first coefficient value x^0.</param>
        /// <param name="secondCoeffientValue">The second coefficient value x^1.</param>
        public SimplePolynomial(double firstCoeffientValue, double secondCoeffientValue)
        {
            this.coefficients = new Double[2];
            this.coefficients[0] = firstCoeffientValue;
            this.coefficients[1] = secondCoeffientValue;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="SimplePolynomial"/> class.
        /// </summary>
        /// <param name="firstCoefficientValue">The first coefficient value x^0.</param>
        /// <param name="secondCoefficientValue">The second coefficient value x^1.</param>
        /// <param name="thirdCoefficientValue">The third coefficient value x^2.</param>
        public SimplePolynomial(double firstCoefficientValue, double secondCoefficientValue,
                                double thirdCoefficientValue)
        {
            this.coefficients = new Double[3];
            this.coefficients[0] = firstCoefficientValue;
            this.coefficients[1] = secondCoefficientValue;
            this.coefficients[2] = thirdCoefficientValue;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="SimplePolynomial"/> class.
        /// </summary>
        /// <param name="data">The coefficient data of the polynomial.</param>
        public SimplePolynomial(double[] data)
        {
            this.coefficients = data;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="SimplePolynomial"/> class.
        /// </summary>
        /// <param name="poly">The polynomial to clone.</param>
        public SimplePolynomial(SimplePolynomial poly)
        {
            if (poly == (SimplePolynomial) null)
            {
                throw new ArgumentNullException("poly");
            }

            double[] tempuri = poly.Coefficients;
            this.coefficients = new double[poly.Degree + 1];

            for (int i = 0; i < tempuri.Length; i++)
            {
                this.coefficients[i] = tempuri[i];
            }
        }

        /// <summary>
        /// Gets the degree of the polynomial.
        /// </summary>
        /// <value>The degree of the polynomial.</value>
        public int Degree
        {
            get { return this.coefficients.Length - 1; }
        }

        /// <summary>
        /// Sets the coefficient of the specified rank to zero.
        /// </summary>
        /// <param name="rank">he rank where the coefficient should be set to zero.</param>
        public void SetRankToZero(int rank)
        {
            if ((uint) rank >= (uint) (this.coefficients.Length))
            {
                throw new ArgumentException("complex reason");
            }

            if (rank < this.coefficients.Length)
            {
                this.coefficients[rank] = 0;
            }
            else
            {
                throw new PolynomialRankNotFoundException("Polynomial Degree not found.");
            }
        }

        /// <summary>
        /// Rounds the coefficients of the polynomial.
        /// </summary>
        /// <param name="decimals">The decimal precision.</param>
        public void RoundCoefficients(int decimals)
        {
            if (decimals < 0)
            {
                throw new ArgumentException("decimals < 0", "decimals");
            }
            if (15 < decimals)
            {
                throw new ArgumentException("15 < decimals", "decimals");
            }

            for (int i = 0; i < this.coefficients.Length; i++)
            {
                this.coefficients[i] = Math.Round(this.coefficients[i], decimals);
            }
        }

        /// <summary>
        /// Raises the specified power for each coefficient of the polynomial.
        /// </summary>
        /// <param name="power">The number to raises the power.</param>
        public void PowCoefficients(double power)
        {
            for (int i = 0; i < this.coefficients.Length; i++)
            {
                this.coefficients[i] = Math.Pow(this.coefficients[i], power);
            }
        }

        /// <summary>
        /// Raises the specified power of the polynomial.
        /// </summary>
        /// <param name="power">The specified power.</param>
        public void Pow(int power)
        {
            SimplePolynomial pow = this.Copy();
            SimplePolynomial original = this;

            for (int i = 0; i < power; i++)
            {
                original *= pow;
            }

            this.coefficients = original.Coefficients;
        }

        /// <summary>
        /// Calculates the square root of the coefficients of the polynomial.
        /// </summary>
        public void SqrtCoefficients()
        {
            for (int i = 0; i < this.coefficients.Length; i++)
            {
                this.coefficients[i] = Math.Sqrt(this.coefficients[i]);
            }
        }

        /// <summary>
        ///  Calculates the root of the coefficients of the polynomial.
        /// </summary>
        /// <param name="root">The root.</param>
        public void RootCoefficients(double root)
        {
            for (int i = 0; i < this.coefficients.Length; i++)
            {
                this.coefficients[i] = Math.Pow(this.coefficients[i], 1 / root);
            }
        }

        /// <summary>
        /// Applies the log10 to every coefficient of the polynomial.
        /// </summary>
        public void Log10Coefficients()
        {
            for (int i = 0; i < this.coefficients.Length; i++)
            {
                this.coefficients[i] = Math.Log10(this.coefficients[i]);
            }
        }

        /// <summary>
        /// Applies the log to every coefficient of the polynomial.
        /// </summary>
        public void LogCoefficients()
        {
            for (int i = 0; i < this.coefficients.Length; i++)
            {
                this.coefficients[i] = Math.Log(this.coefficients[i]);
            }
        }

        /// <summary>
        /// Applies a coefficient to the current polynomial.
        /// </summary>
        /// <param name="applyCoefficient">The to apply coefficient.</param>
        public void ApplyCoefficient(double applyCoefficient)
        {
            this.ShiftLeft();
            this.coefficients[0] = applyCoefficient;
        }

        /// <summary>
        /// Sets the value at a specified rank.
        /// </summary>
        /// <param name="rank">The rank where the coefficient should be set.</param>
        /// <param name="value">The value of the coefficient.</param>
        public void SetValueAtRank(int rank, double value)
        {
            if ((uint) rank >= (uint) (this.coefficients.Length))
            {
                throw new ArgumentException("complex reason");
            }

            if (rank < this.coefficients.Length)
            {
                this.coefficients[rank] = value;
            }
            else
            {
                throw new PolynomialRankNotFoundException("Polynomial Degree not found.");
            }
        }

        /// <summary>
        /// Adds the value at a specified rank.
        /// </summary>
        /// <param name="rank">The rank where the coefficient should be added.</param>
        /// <param name="value">The add value of the coefficient.</param>
        public void AddValueAtRank(int rank, double value)
        {
            if ((uint) rank >= (uint) (this.coefficients.Length))
            {
                throw new ArgumentException("complex reason");
            }

            if (rank < this.coefficients.Length)
            {
                this.coefficients[rank] += value;
            }
            else
            {
                throw new PolynomialRankNotFoundException("Polynomial Degree not found.");
            }
        }

        /// <summary>
        /// Subtracts the value at a specified rank.
        /// </summary>
        /// <param name="rank">The rank where the coefficient should be subtract.</param>
        /// <param name="value">The substract value of the coefficient.</param>
        public void SubtractValueAtRank(int rank, double value)
        {
            if ((uint) rank >= (uint) (this.coefficients.Length))
            {
                throw new ArgumentException("complex reason");
            }

            if (rank < this.coefficients.Length)
            {
                this.coefficients[rank] -= value;
            }
            else
            {
                throw new PolynomialRankNotFoundException("Polynomial Degree not found.");
            }
        }

        /// <summary>
        /// Solves the square function by the PQ formula.
        /// </summary>
        /// <param name="p">The p value.</param>
        /// <param name="q">The q value.</param>
        /// <returns>The roots of the function.</returns>
        public static double[] PQFormlarSolving(double p, double q)
        {
            double[] result = new double[2];

            double preValue = -(p / 2);
            double rootValue = Math.Pow((p / 2), 2) - q;

            if (rootValue > 0)
            {
                result[0] = preValue + rootValue;
                result[1] = preValue - rootValue;
            }
            else
            {
                result[0] = preValue;
            }

            return result;
        }

        /// <summary>
        /// Checks if the parameter for x is root of the polynomial.
        /// </summary>
        /// <param name="value">The value to check.</param>
        /// <returns>
        /// 	<c>true</c> if the specified value is root; otherwise, <c>false</c>.
        /// </returns>
        public bool IsRoot(double value)
        {
            return this.SolveAt(value) == 0;
        }

        /// <summary>
        /// Gets the coefficient at a special rank.
        /// </summary>
        /// <param name="rank">The rank.</param>
        /// <returns>The coefficient of the rank.</returns>
        public double ValueAtRank(int rank)
        {
            if ((uint) rank >= (uint) (this.coefficients.Length))
            {
                throw new ArgumentException("complex reason");
            }

            if (rank < this.coefficients.Length)
            {
                return this.coefficients[rank];
            }

            throw new PolynomialRankNotFoundException("Polynomial Degree not found.");
        }

        /// <summary>
        /// Multiplies the polynomial with a scalar.
        /// </summary>
        /// <param name="scalar">The scalar value.</param>
        public void MultiplyWithScalar(int scalar)
        {
            this.MultiplyWithScalar((double) scalar);
        }

        /// <summary>
        /// Multiplies the polynomial with a scalar.
        /// </summary>
        /// <param name="scalar">The scalar value.</param>
        public void MultiplyWithScalar(double scalar)
        {
            for (int i = 0; i < this.coefficients.Length; i++)
            {
                this.SetValueAtRank(i, this.ValueAtRank(i) * scalar);
            }
        }

        /// <summary>
        /// Divides the polynomial through scalar.
        /// </summary>
        /// <param name="scalar">The scalar value.</param>
        public void DivideWithScalar(int scalar)
        {
            this.DivideWithScalar((double) scalar);
        }

        /// <summary>
        /// Divides the polynomial through scalar.
        /// </summary>
        /// <param name="scalar">The scalar value.</param>
        public void DivideWithScalar(double scalar)
        {
            for (int i = 0; i < this.coefficients.Length; i++)
            {
                this.SetValueAtRank(i, this.ValueAtRank(i) / scalar);
            }
        }

        /// <summary>
        /// Implements the operator +.
        /// </summary>
        /// <param name="poly">The first polynomial.</param>
        /// <param name="add">The second polynomial.</param>
        /// <returns>The result of the operator.</returns>
        public static SimplePolynomial operator +(SimplePolynomial poly, SimplePolynomial add)
        {
            if (poly == (SimplePolynomial) null)
            {
                throw new ArgumentNullException("poly");
            }

            if (add == (SimplePolynomial) null)
            {
                throw new ArgumentNullException("add");
            }

            SimplePolynomial smallPolynom;
            SimplePolynomial bigPolynom;

            if (poly.Degree < add.Degree)
            {
                smallPolynom = poly;
                bigPolynom = add;
            }
            else
            {
                smallPolynom = add;
                bigPolynom = poly;
            }

            for (int i = 0; i <= smallPolynom.Degree; i++)
            {
                double newValue = smallPolynom.ValueAtRank(i) + bigPolynom.ValueAtRank(i);
                bigPolynom.SetValueAtRank(i, newValue);
            }

            return bigPolynom;
        }

        /// <summary>
        /// Implements the operator ==.
        /// </summary>
        /// <param name="a">The first polynomial.</param>
        /// <param name="b">The second polynomial.</param>
        /// <returns>The result of the operator.</returns>
        public static bool operator ==(SimplePolynomial a, SimplePolynomial b)
        {
            if (System.Object.ReferenceEquals(a, b))
            {
                return true;
            }

            if (((object) a == null) || ((object) b == null))
            {
                return false;
            }

            if (a.Coefficients.Length != b.Coefficients.Length)
            {
                return false;
            }

            for (int i = 0; i < a.Coefficients.Length; i++)
            {
                if (a.Coefficients[i] != b.Coefficients[i])
                {
                    return false;
                }
            }

            return true;
        }

        /// <summary>
        /// Implements the operator !=.
        /// </summary>
        /// <param name="a">The first polynomial.</param>
        /// <param name="b">The second polynomial.</param>
        /// <returns>The result of the operator.</returns>
        public static bool operator !=(SimplePolynomial a, SimplePolynomial b)
        {
            return !(a == b);
        }

        /// <summary>
        /// Implements the operator -.
        /// </summary>
        /// <param name="poly">The first polynomial.</param>
        /// <param name="sub">The second polynomial.</param>
        /// <returns>The result of the operator.</returns>
        public static SimplePolynomial operator -(SimplePolynomial poly, SimplePolynomial sub)
        {
            if (poly == (SimplePolynomial) null)
            {
                throw new ArgumentNullException("poly");
            }

            if (sub == (SimplePolynomial) null)
            {
                throw new ArgumentNullException("sub");
            }

            SimplePolynomial smallPolynom = sub;
            SimplePolynomial bigPolynom = poly;

            if (poly.Degree < sub.Degree)
            {
                bigPolynom = new SimplePolynomial(smallPolynom.Degree);
                bigPolynom += poly;
            }

            for (int i = 0; i <= smallPolynom.Degree; i++)
            {
                double newValue = bigPolynom.ValueAtRank(i) - smallPolynom.ValueAtRank(i);
                bigPolynom.SetValueAtRank(i, newValue);
            }

            return bigPolynom;
        }

        /// <summary>
        /// Implements the operator *.
        /// </summary>
        /// <param name="poly">The polynomial.</param>
        /// <param name="multiply">The multiply.</param>
        /// <returns>The result of the operator.</returns>
        public static SimplePolynomial operator *(SimplePolynomial poly, SimplePolynomial multiply)
        {
            if (poly == (SimplePolynomial) null)
            {
                throw new ArgumentNullException("poly");
            }

            if (multiply == (SimplePolynomial) null)
            {
                throw new ArgumentNullException("multiply");
            }

            if (poly.coefficients == (double[]) null)
            {
                throw new ArgumentNullException("poly");
            }

            if (multiply.coefficients == (double[]) null)
            {
                throw new ArgumentNullException("multiply");
            }

            SimplePolynomial result = new SimplePolynomial(poly.Degree + multiply.Degree);

            for (int i = 0; i <= poly.Degree; i++)
            {
                for (int j = 0; j <= multiply.Degree; j++)
                {
                    result.AddValueAtRank(i + j, poly.ValueAtRank(i) * multiply.ValueAtRank(j));
                }
            }

            result.RemoveLeadingZeros();

            return result;
        }

        /// <summary>
        /// Implements the operator &lt;&lt;.
        /// </summary>
        /// <param name="a">The polynomial to shift.</param>
        /// <param name="n">The number of positions to shift.</param>
        /// <returns>The result of the operator.</returns>
        public static SimplePolynomial operator <<(SimplePolynomial a, int n)
        {
            SimplePolynomial result = a.Copy();

            result.ShiftLeft(n);

            return result;
        }

        /// <summary>
        /// Implements the operator &gt;&gt;.
        /// </summary>
        /// <param name="a">The polynomial to shift.</param>
        /// <param name="n">The number of positions to shift.</param>
        /// <returns>The result of the operator.</returns>
        public static SimplePolynomial operator >>(SimplePolynomial a, int n)
        {
            SimplePolynomial result = a.Copy();

            result.ShiftRight(n);

            return result;
        }

        /// <summary>
        /// Calculates one root of the polynomial by using the Newton-Raphson method.
        /// </summary>
        /// <param name="startvalue">The start value.</param>
        /// <param name="iterations">The number of iterations for finding a root.</param>
        /// <returns>One root of the polynomial.</returns>
        public double FindRoot(double startvalue, int iterations)
        {
            SimplePolynomial derivation = this.Derivative();

            for (int i = 0; i < iterations; i++)
            {
                startvalue = startvalue -
                             (this.SolveAt(startvalue) / derivation.SolveAt(startvalue));
            }

            return startvalue;
        }

        /// <summary>
        /// Creates the first derivative of the polynomial.
        /// </summary>
        /// <returns>Returns the derivative of the polynomial.</returns>
        public SimplePolynomial Derivative()
        {
            SimplePolynomial result = new SimplePolynomial(this.Degree - 1);

            for (int i = 1; i < this.coefficients.Length; i++)
            {
                result.SetValueAtRank(i - 1, i * this.coefficients[i]);
            }

            return result;
        }

        /// <summary>
        /// Normalizes the polynomial.
        /// </summary>
        public void Normalize()
        {
            double divisor = this.GetCoefficientOfBiggestExponent();

            if (divisor != 0)
            {
                for (int i = 0; i < this.coefficients.Length; i++)
                {
                    this.coefficients[i] /= divisor;
                }
            }
        }

        /// <summary>
        /// Use Horner's method to compute and return the polynomial evaluated at x.
        /// </summary>
        /// <param name="x">The x value.</param>
        /// <returns>The evaluated value of the polynomial.</returns>
        public double Evaluate(int x)
        {
            double tempuri = 0;

            for (int i = this.coefficients.Length - 1; i >= 0; i--)
            {
                tempuri = this.coefficients[i] + (x * tempuri);
            }

            return tempuri;
        }

        /// <summary>
        /// Calculates the polynomial with a specified x number.
        /// </summary>
        /// <param name="x">The x value.</param>
        /// <returns>Returns the absolute value of the polynomial.</returns>
        public override double SolveAt(double x)
        {
            double result = 0;

            for (int i = 0; i < this.coefficients.Length; i++)
            {
                result += this.coefficients[i] * Math.Pow(x, i);
            }

            return result;
        }

        /// <summary>
        /// Checks if the polynomial is a Zero Polynomial.
        /// </summary>
        /// <returns>
        /// 	<c>true</c> if this polynomial is zero; otherwise, <c>false</c>.
        /// </returns>
        public bool IsZero()
        {
            for (int i = 0; i < this.coefficients.Length; i++)
            {
                if (this.coefficients[i] != 0)
                {
                    return false;
                }
            }

            return true;
        }

        /// <summary>
        /// Removes the leading zeros of the polynomial.
        /// </summary>
        public void RemoveLeadingZeros()
        {
            int i = this.coefficients.Length - 1;

            while ((i > 0) && (this.coefficients[i] == 0))
            {
                i--;
            }

            double[] newCoefficients = new double[i + 1];

            for (int j = 0; j < newCoefficients.Length; j++)
            {
                newCoefficients[j] = this.coefficients[j];
            }

            this.coefficients = newCoefficients;
        }

        /// <summary>
        /// Gets the coefficient of lowest exponent.
        /// </summary>
        /// <returns>Returns the coefficient of lowest exponent.</returns>
        public double GetCoefficientOfLowestExponent()
        {
            return this.coefficients[0];
        }

        /// <summary>
        /// Gets the coefficient of biggest exponent.
        /// </summary>
        /// <returns>Returns the coefficient of biggest exponent.</returns>
        public double GetCoefficientOfBiggestExponent()
        {
            return this.coefficients[this.coefficients.Length - 1];
        }

        /// <summary>
        /// Gets the biggest coefficient of the polynomial.
        /// </summary>
        /// <returns>The biggest coefficient of the polynomial.</returns>
        public double GetBiggestCoefficient()
        {
            double biggest = this.coefficients[0];

            for (int i = 1; i < this.coefficients.Length; i++)
            {
                if (this.coefficients[i] > biggest)
                {
                    biggest = this.coefficients[i];
                }
            }

            return biggest;
        }

        /// <summary>
        /// Gets smallest coefficient of the polynomial.
        /// </summary>
        /// <returns>The smallest coefficient of the polynomial.</returns>
        public double GetSmallestCoefficient()
        {
            double biggest = this.coefficients[0];

            for (int i = 1; i < this.coefficients.Length; i++)
            {
                if (this.coefficients[i] < biggest)
                {
                    biggest = this.coefficients[i];
                }
            }

            return biggest;
        }

        /// <summary>
        /// Gets the maximum degree of two polynomials.
        /// </summary>
        /// <param name="a">The first polynomial.</param>
        /// <param name="b">The second polynomial.</param>
        /// <returns>The biggest degree of the two polynomials.</returns>
        public static int Max(SimplePolynomial a, SimplePolynomial b)
        {
            if (a == (SimplePolynomial) null)
            {
                throw new ArgumentNullException("a");
            }

            if (b == (SimplePolynomial) null)
            {
                throw new ArgumentNullException("b");
            }

            if (a.coefficients == (double[]) null)
            {
                throw new ArgumentNullException("a");
            }

            if (b.coefficients == (double[]) null)
            {
                throw new ArgumentNullException("b");
            }

            if (a.Degree < b.Degree)
            {
                return b.Degree;
            }

            return a.Degree;
        }

        /// <summary>
        /// Gets the minimum degree of two polynomials.
        /// </summary>
        /// <param name="a">The first polynomial.</param>
        /// <param name="b">The second polynomial.</param>
        /// <returns>The smallest degree of the two polynomials.</returns>
        public static int Min(SimplePolynomial a, SimplePolynomial b)
        {
            if (a == (SimplePolynomial) null)
            {
                throw new ArgumentNullException("a");
            }

            if (b == (SimplePolynomial) null)
            {
                throw new ArgumentNullException("b");
            }

            if (a.coefficients == (double[]) null)
            {
                throw new ArgumentNullException("a");
            }

            if (b.coefficients == (double[]) null)
            {
                throw new ArgumentNullException("b");
            }

            if (a.Degree < b.Degree)
            {
                return a.Degree;
            }

            return b.Degree;
        }

        /// <summary>
        /// Generates a random polynomial.
        /// </summary>
        /// <param name="rank">The degree of the random polynomial.</param>
        /// <returns>A random polynomial.</returns>
        public static SimplePolynomial GenerateRandomPolynomial(int rank)
        {
            if (rank < 1)
            {
                throw new ArgumentException("rank < 1", "rank");
            }

            Random random = new Random();
            SimplePolynomial result = new SimplePolynomial(rank);

            for (int i = 0; i <= result.Degree; i++)
            {
                result.SetValueAtRank(i, random.NextDouble());
            }

            return result;
        }

        /// <summary>
        /// Fabses a specified number always to a positive number.
        /// </summary>
        /// <param name="number">The number to fab.</param>
        /// <returns>The fabed number.</returns>
        private static double Fabs(double number)
        {
            if (number < 0)
            {
                return -number;
            }

            return number;
        }

        /// <summary>
        /// Shifts the polynomial coefficients one to the left.
        /// </summary>
        public void ShiftLeft()
        {
            this.ShiftLeft(1);
        }

        /// <summary>
        /// Shifts the polynomial coefficients n-times to the left. If the time parameter is
        /// negative it will execute the ShiftRight method. 
        /// </summary>
        /// <param name="times">The times to shift.</param>
        public void ShiftLeft(int times)
        {
            if (times < 0)
            {
                this.ShiftRight(-times);
                return;
            }

            double[] result = new double[times + this.coefficients.Length];

            for (int i = times; i < result.Length; i++)
            {
                result[i] = this.coefficients[i - times];
            }

            this.coefficients = result;
        }

        /// <summary>
        /// Shifts the polynomial coefficients one to the right.
        /// </summary>
        public void ShiftRight()
        {
            this.ShiftRight(1);
        }

        /// <summary>
        /// Shifts the polynomial coefficients n-times to the right. If the time parameter is
        /// negative it will execute the ShiftLeft method. 
        /// </summary>
        /// <param name="times">The times to shift.</param>
        public void ShiftRight(int times)
        {
            if (times < 0)
            {
                this.ShiftLeft(-times);
                return;
            }

            if (this.coefficients.Length <= times)
            {
                this.coefficients = new double[] {0.00};
                return;
            }

            double[] result = new double[this.coefficients.Length - times];

            for (int i = 0; i < result.Length; i++)
            {
                result[i] = this.coefficients[i + times];
            }

            this.coefficients = result;
        }

        /// <summary>
        /// Gets or sets the polynomial coefficients.
        /// </summary>
        /// <value>The polynomial coefficients.</value>
        public Double[] Coefficients
        {
            get { return coefficients; }
        }

        /// <summary>
        /// Makes a copy of the current polynomial.
        /// </summary>
        /// <returns>Returns a copy of the current polynomial</returns>
        public SimplePolynomial Copy()
        {
            return new SimplePolynomial((double[]) this.coefficients.Clone());
        }

        /// <summary>
        /// Converts a SimplePolynomial to a Polynomial.
        /// </summary>
        /// <returns>The converted polynomial.</returns>
        public Polynomial ToPolynomial()
        {
            Polynomial result = new Polynomial();

            for (int i = 0; i < this.coefficients.Length; i++)
            {
                result.AddInFrontOf(new PolynomialComponent(this.coefficients[i], i));
            }

            return result;
        }

        /// <summary>
        /// Converts the polynomial to a complex polynomial.
        /// </summary>
        /// <returns>The converted complex polynomial.</returns>
        public ComplexPolynomial ToComplexPolynomial()
        {
            List<ComplexPolynomialComponent> data = new List<ComplexPolynomialComponent>();

            for (int i = 0; i < this.coefficients.Length; i++)
            {
                data.Add(new ComplexPolynomialComponent(new ComplexNumber
                                                            (this.coefficients[i]), i));
            }

            return new ComplexPolynomial(data);
        }

        /// <summary>
        /// Converts the polynomial to a rational polynomial.
        /// </summary>
        /// <returns>The converted rational polynomial.</returns>
        public SimpleRationalPolynomial ToRationalPolynomial()
        {
            return new SimpleRationalPolynomial(this.Copy(), new SimplePolynomial(1));
        }

        /// <summary>
        /// Determines whether the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>.
        /// </summary>
        /// <param name="obj">The <see cref="T:System.Object"/> to compare with the current <see cref="T:System.Object"/>.</param>
        /// <returns>
        /// true if the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>; otherwise, false.
        /// </returns>
        /// <exception cref="T:System.NullReferenceException">The <paramref name="obj"/> parameter is null.</exception>
        public override bool Equals(object obj)
        {
            if (obj != (object) null && !(obj is SimplePolynomial))
            {
                throw new ArgumentException("complex reason", "obj");
            }
            if (obj == (object) null)
            {
                throw new ArgumentNullException("obj");
            }
            if (((SimplePolynomial) obj).coefficients == (double[]) null)
            {
                throw new ArgumentNullException("obj");
            }

            SimplePolynomial compare = (SimplePolynomial) obj;

            if (this.coefficients.Length == compare.Degree)
            {
                for (int i = 0; i < this.coefficients.Length; i++)
                {
                    if (this.coefficients[i] != compare.ValueAtRank(i))
                    {
                        return false;
                    }
                }

                return true;
            }

            return false;
        }

        /// <summary>
        /// Serves as a hash function for a particular type.
        /// </summary>
        /// <returns>
        /// A hash code for the current <see cref="T:System.Object"/>.
        /// </returns>
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        /// <summary>
        /// Returns a <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
        /// </returns>
        public override string ToString()
        {
            String result = "";

            //if(coefficients.Length < 1)
            //{
            //    return result;
            //}

            if (this.coefficients[this.coefficients.Length - 1] < 0)
            {
                result += "-";
            }

            for (int i = this.coefficients.Length - 1; i > 0; i--)
            {
                result += SimplePolynomial.Fabs(this.coefficients[i]).ToString() + "x^" + i;

                if (this.coefficients[i - 1] > 0)
                {
                    result += " + ";
                }
                else
                {
                    result += " - ";
                }
            }

            return result + SimplePolynomial.Fabs(this.coefficients[0]) + "x^0";
        }
    }
}